#include "raylib.h"
#include "raymath.h"
#include <math.h>

// 光线投射检查是否可见
bool IsPositionVisible(Vector3 start, Vector3 end, Model *walls, int wallCount, BoundingBox *wallBoxes)
{
    Ray ray = { start, Vector3Normalize(Vector3Subtract(end, start)) };
    float maxDistance = Vector3Distance(start, end);
    
    for (int i = 0; i < wallCount; i++) {
        RayCollision collision = GetRayCollisionBox(ray, wallBoxes[i]);
        if (collision.hit && collision.distance < maxDistance) {
            return false; // 有墙壁阻挡
        }
    }
    return true;
}

int main(void)
{
    const int screenWidth = 800;
    const int screenHeight = 450;
    
    InitWindow(screenWidth, screenHeight, "Dark Maze Exploration");
    
    Camera camera = { 0 };
    camera.position = (Vector3){ 0.0f, 1.0f, 0.0f };
    camera.target = (Vector3){ 0.0f, 1.0f, 1.0f };
    camera.up = (Vector3){ 0.0f, 1.0f, 0.0f };
    camera.fovy = 60.0f;
    camera.projection = CAMERA_PERSPECTIVE;
    
    // 创建迷宫墙壁
    #define WALL_COUNT 10
    Model walls[WALL_COUNT];
    BoundingBox wallBoxes[WALL_COUNT];
    
    // 简单迷宫布局
    Vector3 wallPositions[WALL_COUNT] = {
        { 0, 0, 5 }, { 3, 0, 3 }, { -3, 0, 3 }, { 0, 0, -5 },
        { 5, 0, 0 }, { -5, 0, 0 }, { 2, 0, -2 }, { -2, 0, -2 },
        { 4, 0, -3 }, { -4, 0, -3 }
    };
    
    for (int i = 0; i < WALL_COUNT; i++) {
        walls[i] = LoadModelFromMesh(GenMeshCube(2.0f, 3.0f, 0.5f));
        wallBoxes[i] = (BoundingBox){
            (Vector3){ wallPositions[i].x - 1.0f, wallPositions[i].y - 1.5f, wallPositions[i].z - 0.25f },
            (Vector3){ wallPositions[i].x + 1.0f, wallPositions[i].y + 1.5f, wallPositions[i].z + 0.25f }
        };
    }
    
    // 地板
    Model floor = LoadModelFromMesh(GenMeshPlane(20.0f, 20.0f, 1, 1));
    
    // 简化着色器 - 没有环境光！
    Shader darkShader = LoadShaderFromMemory(
    "#version 330 core\n"
    "in vec3 vertexPosition; in vec2 vertexTexCoord; in vec3 vertexNormal;"
    "uniform mat4 mvp; uniform mat4 matModel;"
    "out vec2 fragTexCoord; out vec3 fragPosition; out vec3 fragNormal;"
    "void main()"
    "{"
    "    fragTexCoord = vertexTexCoord;"
    "    fragPosition = vec3(matModel * vec4(vertexPosition, 1.0));"
    "    fragNormal = normalize(vec3(matModel * vec4(vertexNormal, 0.0)));"
    "    gl_Position = mvp * vec4(vertexPosition, 1.0);"
    "}",
    
    "#version 330 core\n"
    "in vec2 fragTexCoord; in vec3 fragPosition; in vec3 fragNormal;"
    "uniform vec3 flashlightPos; uniform vec3 flashlightDir;"
    "uniform float visible; uniform vec3 flashlightColor;"
    "out vec4 finalColor;"
    "void main()"
    "{"
    "    vec3 objectColor = vec3(0.7, 0.7, 0.7);"
    "    if (visible < 0.5) {"
    "        finalColor = vec4(0.0, 0.0, 0.0, 1.0); return;"
    "    }"
    "    vec3 lightDir = normalize(flashlightPos - fragPosition);"
    "    vec3 normal = normalize(fragNormal);"
    "    float theta = dot(lightDir, normalize(-flashlightDir));"
    "    float cutoff = 0.9;"
    "    float intensity = clamp((theta - 0.7) / 0.2, 0.0, 1.0);"
    "    if (theta < cutoff) {"
    "        finalColor = vec4(0.0, 0.0, 0.0, 1.0); return;"
    "    }"
    "    float diff = max(dot(normal, lightDir), 0.0);"
    "    float distance = length(flashlightPos - fragPosition);"
    "    float attenuation = 1.0 / (1.0 + 0.1 * distance + 0.01 * distance * distance);"
    "    vec3 result = diff * objectColor * flashlightColor * intensity * attenuation;"
    "    finalColor = vec4(result, 1.0);"
    "}"
);
    
    // 应用着色器
    for (int i = 0; i < WALL_COUNT; i++) {
        walls[i].materials[0].shader = darkShader;
    }
    floor.materials[0].shader = darkShader;
    
    // 获取uniform位置
    int flashlightPosLoc = GetShaderLocation(darkShader, "flashlightPos");
    int flashlightDirLoc = GetShaderLocation(darkShader, "flashlightDir");
    int visibleLoc = GetShaderLocation(darkShader, "visible");
    int flashlightColorLoc = GetShaderLocation(darkShader, "flashlightColor");
    
    Vector3 flashlightColor = { 1.0f, 1.0f, 0.9f };
    
    SetTargetFPS(60);
    
    while (!WindowShouldClose())
    {
        // 更新相机（第一人称）
        UpdateCamera(&camera, CAMERA_FIRST_PERSON);
        
        // 手电筒位置和方向
        Vector3 flashlightPos = camera.position;
        Vector3 flashlightDir = Vector3Normalize(Vector3Subtract(camera.target, camera.position));
        
        BeginDrawing();
        ClearBackground(BLACK); // 背景完全黑色
        
        BeginMode3D(camera);
        
        // 绘制所有物体，检查每个位置是否可见
        for (int i = 0; i < WALL_COUNT; i++) {
            float visible = IsPositionVisible(flashlightPos, wallPositions[i], walls, WALL_COUNT, wallBoxes) ? 1.0f : 0.0f;
            
            SetShaderValue(darkShader, flashlightPosLoc, &flashlightPos, SHADER_UNIFORM_VEC3);
            SetShaderValue(darkShader, flashlightDirLoc, &flashlightDir, SHADER_UNIFORM_VEC3);
            SetShaderValue(darkShader, visibleLoc, &visible, SHADER_UNIFORM_FLOAT);
            SetShaderValue(darkShader, flashlightColorLoc, &flashlightColor, SHADER_UNIFORM_VEC3);
            
            DrawModel(walls[i], wallPositions[i], 1.0f, WHITE);
        }
        
        // 地板也应用相同的逻辑
        float floorVisible = IsPositionVisible(flashlightPos, (Vector3){0,0,0}, walls, WALL_COUNT, wallBoxes) ? 1.0f : 0.0f;
        SetShaderValue(darkShader, visibleLoc, &floorVisible, SHADER_UNIFORM_FLOAT);
        DrawModel(floor, (Vector3){0, -1.5f, 0}, 1.0f, WHITE);
        
        EndMode3D();
        
        // UI
        DrawText("WASD: 移动, 鼠标: 视角", 10, 10, 20, GREEN);
        DrawText("黑暗迷宫探索 - 光线不能穿墙", 10, 40, 20, YELLOW);
        
        EndDrawing();
    }
    
    // 清理资源
    for (int i = 0; i < WALL_COUNT; i++) {
        UnloadModel(walls[i]);
    }
    UnloadModel(floor);
    UnloadShader(darkShader);
    CloseWindow();
    
    return 0;
}